package com.hzhq.contract.controller;

import cn.hutool.core.collection.CollUtil;
import com.hzhq.contract.bean.dto.ContractDTO;
import com.hzhq.contract.bean.dto.ContractStatusDTO;
import com.hzhq.contract.bean.entity.ContractStatus;
import com.hzhq.contract.bean.vo.ContractStatusVO;
import com.hzhq.contract.convert.ContractStatusConvertBasic;
import com.hzhq.contract.result.Result;
import com.hzhq.contract.service.ContractService;
import com.hzhq.contract.service.ContractStatusService;
import com.hzhq.contract.status.DefaultValue;
import com.hzhq.contract.util.ConvertUtil;
import com.hzhq.contract.util.Page2ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


import javax.validation.Valid;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author: hzhq1255
 * @Mail: hzhq1255@163.com
 * @Date: 2021/5/3 22:50
 * @Desc:
 */
@Api(tags = "合同状态管理")
@CrossOrigin
@RestController
@ResponseBody
@RequestMapping("/api/v1/contracts")
public class ContractStatusController {


    @Autowired
    ContractService contractService;


    @Autowired
    ContractStatusService statusService;

    @Autowired
    MongoTemplate mongoTemplate;

    private static final BigDecimal DEFAULT_MIN_PAYMENT = BigDecimal.valueOf(Long.MIN_VALUE);

    private static final BigDecimal DEFAULT_MAX_PAYMENT = BigDecimal.valueOf(Long.MAX_VALUE);


    @ApiOperation("合同收支状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId",value = "contractId",paramType = "path",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "currentPage",value = "currentPage",paramType = "path",dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize",value = "pageSize",paramType = "path",dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "statusName",value = "statusName",paramType = "query",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "desc",value = "desc",paramType = "query",dataType = "String", dataTypeClass = String.class),
    })
    @ResponseBody
    @RequestMapping(value = "/{contractId}/statuses/currentPage/{currentPage}/pageSize/{pageSize}",method = RequestMethod.GET)
    private Result<Object> getStatusPageByContractId(@PathVariable("contractId") String contractId,
                                                     @PathVariable("currentPage") Integer currentPage,
                                                     @PathVariable("pageSize") Integer pageSize,
                                                     @RequestParam(value = "statusName",required = false) String statusName,
                                                     @RequestParam(value = "desc",required = false) String desc){
        ContractStatusDTO status = new ContractStatusDTO();
        if (ObjectId.isValid(contractId)){
//            System.out.println("controller  "+contractId);
            status.setContractId(contractId);
        }
        if (null != statusName && !"".equals(statusName)){
            status.setStatusName(statusName);
        }
        if (null != desc && !"".equals(desc)){
            status.setDesc(desc);
        }
        status.setDeleted(DefaultValue.NOT_DELETED);
        Page<ContractStatusVO> statusVOPage = statusService.searchAllPages(status,currentPage,pageSize).map(ContractStatusConvertBasic.INSTANCE::dtoToVo);
        return Result.successWithData(Page2ResultUtil.getPageData(statusVOPage));

    }

    @ApiOperation("合同收支状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId",value = "contractId",paramType = "path",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "currentPage",value = "currentPage",paramType = "path",dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize",value = "pageSize",paramType = "path",dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "statusName",value = "statusName",paramType = "query",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "desc",value = "desc",paramType = "query",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "maxPayment",value = "maxPayment",paramType = "query",dataType = "BigDecimal", dataTypeClass = BigDecimal.class),
            @ApiImplicitParam(name = "minPayment",value = "minPayment",paramType = "query",dataType = "BigDecimal", dataTypeClass = BigDecimal.class),
    })
    @ResponseBody
    @RequestMapping(value = "/{contractId}/statuses/query/currentPage/{currentPage}/pageSize/{pageSize}",method = RequestMethod.GET)
    private Result<Object> getStatusPageByQuery(@PathVariable("contractId") String contractId,
                                                @PathVariable("currentPage") Integer currentPage,
                                                @PathVariable("pageSize") Integer pageSize,
                                                @RequestParam(value = "statusName", required = false) String statusName,
                                                @RequestParam(value = "desc", required = false) String desc,
                                                @RequestParam(value = "maxPayment", required = false) BigDecimal maxPayment,
                                                @RequestParam(value = "minPayment", required = false) BigDecimal minPayment){
        final Query query = new Query();
        final Criteria criteria = new Criteria();
        List<Criteria> ands = new ArrayList<>();
        List<Criteria> ors = new ArrayList<>();
        if (ObjectId.isValid(contractId)){
            ands.add(Criteria.where(ContractStatus.CONTRACT_ID_FIELD).is(new ObjectId(contractId)));
        }
        if ( null != statusName){
            ors.add(Criteria.where(ContractStatus.STATUS_NAME_FIELD).regex("^.*" + statusName + ".*$"));
        }
        if ( null != desc){
            ors.add(Criteria.where(ContractStatus.DESC_FIELD).regex("^.*" + desc + ".*$"));
        }
        if ( null != maxPayment || null != minPayment){
            Criteria paymentCriteria = Criteria.where(ContractStatus.PAYMENT_FIELD);
            if (null != maxPayment){
                paymentCriteria.lte(maxPayment.doubleValue());
            }
            if (null != minPayment){
                paymentCriteria.gte(minPayment.doubleValue());
            }
            ands.add(paymentCriteria);
        }
        ands.add(Criteria.where(ContractStatus.DELETED_FIELD).is(DefaultValue.NOT_DELETED));
        query.addCriteria(criteria.andOperator(ands.toArray(Criteria[]::new))
                .orOperator(ors.toArray(Criteria[]::new)));
        Page<ContractStatusVO> statusVOPage = statusService.searchAllPageByQuery(query,currentPage,pageSize).map(ContractStatusConvertBasic.INSTANCE::dtoToVo);
        return Result.successWithData(Page2ResultUtil.getPageData(statusVOPage));
    }

    @ApiOperation("合同状态保存")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId",value = "contractId",paramType = "path",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "contractStatus",value = "contractStatus",paramType = "body",dataType = "ContractStatusDTO", dataTypeClass = ContractStatusDTO.class),
    })
    @ResponseBody
    @RequestMapping(value = "/{contractId}/statuses" ,method = RequestMethod.POST)
    private Result<Object> save(@PathVariable("contractId") String contractId,
                                @RequestBody @Valid ContractStatusDTO contractStatus,
                                        BindingResult bindingResult
                                        ){
        if (bindingResult.hasErrors()){
            return Result.errorWithMsg(bindingResult.getAllErrors().get(0).getDefaultMessage());
        }
        if (!ObjectId.isValid(contractId)){
            return Result.errorWithMsg("contractId is not valid!");
        }
        if (null == contractStatus.getStatusId()){
            ContractStatusDTO currentStatus = statusService.getOneByContractIdAndStatusName(contractId,contractStatus.getStatusName());
            if ( null != currentStatus){
                return Result.errorWithMsg("收支名称已重复");
            }
            contractStatus.setContractId(contractId);
            contractStatus.setDeleted(DefaultValue.NOT_DELETED);
            contractStatus.setStatusId(new ObjectId().toString());
            ContractDTO contract = contractService.getOneById(contractStatus.getContractId());
            contract.setCurrentAmount(contract.getCurrentAmount().add(contractStatus.getPayment()));
            contractService.save(contract);
            String resultData = statusService.save(contractStatus).getStatusId();
            return Result.successWithMsgAndData("添加成功",resultData);
        }
        ContractStatusDTO currentStatus = statusService.getOneByContractIdAndStatusId(contractId,contractStatus.getStatusId());
        if ( null == currentStatus){
            return Result.errorWithMsg("该收支状态不存在");
        }
        ContractDTO contract = contractService.getOneById(contractStatus.getContractId());
        ContractStatusDTO oldContractStatus = statusService.getOneById(contractStatus.getStatusId());
        BigDecimal bigDecimal = contractStatus.getPayment().subtract(oldContractStatus.getPayment());
        contract.setCurrentAmount(contract.getCurrentAmount().add(bigDecimal));
        contractService.save(contract);
        String resultData = statusService.save(contractStatus).getStatusId();
        return Result.successWithMsgAndData("修改成功",resultData);
    }

    @ApiOperation("合同状态删除")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId",value = "contractId",paramType = "path",dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "statusId",value = "statusId",paramType = "path",dataType = "String", dataTypeClass = String.class),
    })
    @ResponseBody
    @RequestMapping(value = "/{contractId}/statuses/{statusId}" ,method = RequestMethod.DELETE)
    private Result<Object> deleteById(@PathVariable("contractId") String contractId,
                                      @PathVariable("statusId") String statusId){
        if (!ObjectId.isValid(contractId)){
            return Result.errorWithMsg("contractId is not valid!");
        }
        if (!ObjectId.isValid(statusId)){
            return Result.errorWithMsg("statusId is not valid!");
        }
        ContractDTO contract = contractService.getOneById(contractId);
        ContractStatusDTO contractStatus = statusService.getOneById(statusId);
        contract.setCurrentAmount(contract.getCurrentAmount().subtract(contractStatus.getPayment()));
        contractService.save(contract);
        String delId = statusService.deleteById(statusId);
        return Result.successWithData(delId);
    }

}
